/*
 * Copyright 2017 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.servicecomb.loadbalance;

import java.util.Map;

import io.servicecomb.serviceregistry.config.ConfigurePropertyUtils;
import com.netflix.config.DynamicPropertyFactory;

/**
 * configuration items
 *
 */
public final class Configuration {
    //// 2.1 configuration items
    public static final String PROP_ROOT = "cse.loadbalance.";

    public static final String PROP_POLICY = "NFLoadBalancerRuleClassName";

    // default rule
    public static final String PROP_POLICY_ROUNDROBIN = "com.netflix.loadbalancer.RoundRobinRule";

    // 2.0 configuration items
    public static final String PROP_ROOT_20 = "ribbon.";

    // retry configurations
    public static final String PROP_RETRY_ENABLED = "retryEnabled";

    public static final String PROP_RETRY_ONNEXT = "retryOnNext";

    public static final String PROP_RETRY_ONSAME = "retryOnSame";

    // SessionStickinessRule configruation
    public static final String SESSION_TIMEOUT_IN_SECONDS = "SessionStickinessRule.sessionTimeoutInSeconds";

    public static final String SUCCESSIVE_FAILED_TIMES = "SessionStickinessRule.successiveFailedTimes";

    // Filter configurations

    private static final double PERCENT = 100;

    public static final String FILTER_ISOLATION = "isolation.";

    public static final String FILTER_OPEN = "enabled";

    public static final String FILTER_ERROR_PERCENTAGE = "errorThresholdPercentage";

    public static final String FILTER_ENABLE_REQUEST = "enableRequestThreshold";

    public static final String FILTER_SINGLE_TEST = "singleTestTime";

    public static final String TRANSACTIONCONTROL_OPTIONS_PREFIX_PATTERN =
        "cse.loadbalance.%s.transactionControl.options";

    public static final String TRANSACTIONCONTROL_POLICY_KEY_PATTERN = "cse.loadbalance.%s.transactionControl.policy";

    public static final Configuration INSTANCE = new Configuration();

    private Configuration() {
    }

    public String getPolicy(String microservice) {
        return getProperty(PROP_POLICY_ROUNDROBIN,
                PROP_ROOT + microservice + "." + PROP_POLICY,
                PROP_ROOT_20 + microservice + "." + PROP_POLICY,
                PROP_ROOT + PROP_POLICY,
                PROP_ROOT_20 + PROP_POLICY);
    }

    public int getSessionTimeoutInSeconds() {
        final int defaultValue = 30;
        // do not support MicroService level now
        String p = getProperty("30",
                PROP_ROOT + SESSION_TIMEOUT_IN_SECONDS);
        try {
            return Integer.parseInt(p); // can be negative
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public int getSuccessiveFailedTimes() {
        final int defaultValue = 5;
        // do not support MicroService level now
        String p = getProperty("5",
                PROP_ROOT + SUCCESSIVE_FAILED_TIMES);
        try {
            return Integer.parseInt(p); // can be negative
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public boolean isRetryEnabled(String microservice) {
        String p = getProperty("false",
                PROP_ROOT + microservice + "." + PROP_RETRY_ENABLED,
                PROP_ROOT + PROP_RETRY_ENABLED);
        return Boolean.parseBoolean(p);
    }

    public int getRetryOnNext(String microservice) {
        final int defaultValue = 0;
        String p = getProperty("0",
                PROP_ROOT + microservice + "." + PROP_RETRY_ONNEXT,
                PROP_ROOT + PROP_RETRY_ONNEXT);
        try {
            int result = Integer.parseInt(p);
            if (result > 0) {
                return result;
            } else {
                return defaultValue;
            }
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public int getRetryOnSame(String microservice) {
        final int defaultValue = 0;
        String p = getProperty("0",
                PROP_ROOT + microservice + "." + PROP_RETRY_ONSAME,
                PROP_ROOT + PROP_RETRY_ONSAME);
        try {
            int result = Integer.parseInt(p);
            if (result > 0) {
                return result;
            } else {
                return defaultValue;
            }
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public boolean isIsolationFilterOpen(String microservice) {
        String p = getProperty("false",
                PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_OPEN,
                PROP_ROOT + FILTER_ISOLATION + FILTER_OPEN);
        return Boolean.parseBoolean(p);
    }

    public int getErrorThresholdPercentage(String microservice) {
        final int defaultValue = 20;
        String p = getProperty("20",
                PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_ERROR_PERCENTAGE,
                PROP_ROOT + FILTER_ISOLATION + FILTER_ERROR_PERCENTAGE);
        try {
            int result = Integer.parseInt(p);
            if (result <= PERCENT && result > 0) {
                return result;
            } else {
                return defaultValue;
            }
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public int getEnableRequestThreshold(String microservice) {
        final int defaultValue = 20;
        String p = getProperty("20",
                PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_ENABLE_REQUEST,
                PROP_ROOT + FILTER_ISOLATION + FILTER_ENABLE_REQUEST);
        try {
            int result = Integer.parseInt(p);
            if (result > 0) {
                return result;
            } else {
                return defaultValue;
            }
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public int getSingleTestTime(String microservice) {
        final int defaultValue = 10000;
        String p = getProperty("10000",
                PROP_ROOT + microservice + "." + FILTER_ISOLATION + FILTER_SINGLE_TEST,
                PROP_ROOT + FILTER_ISOLATION + FILTER_SINGLE_TEST);
        try {
            int result = Integer.parseInt(p);
            if (result > 0) {
                return result;
            } else {
                return defaultValue;
            }
        } catch (NumberFormatException e) {
            return defaultValue;
        }
    }

    public String getFlowsplitFilterPolicy(String microservice) {
        return getProperty("", String.format(TRANSACTIONCONTROL_POLICY_KEY_PATTERN, microservice));
    }

    public Map<String, String> getFlowsplitFilterOptions(String microservice) {
        String keyPrefix = String.format(TRANSACTIONCONTROL_OPTIONS_PREFIX_PATTERN, microservice);
        return ConfigurePropertyUtils.getPropertiesWithPrefix(keyPrefix);
    }

    private String getProperty(String defaultValue, String... keys) {
        String property = null;
        for (String key : keys) {
            property = DynamicPropertyFactory.getInstance().getStringProperty(key, null).get();
            if (property != null) {
                break;
            }
        }

        if (property != null) {
            return property;
        } else {
            return defaultValue;
        }
    }

    // Gray Release
    public static final String PROP_GRAYRELEASE_ROOT = "cse.grayrelease.";

    public static final String PROP_GRAYRELEASE_POLICYCLASS = "GrayReleaseRuleClassName";

    public static final String RATE_POLICY = "rate.policy";

    public static final String RULE_POLICY = "rule.policy";

    public static final String PROP_GRAYRELEASE_GROUP_POLICY = "group.policy";

    public static final String PROP_GRAYRELEASE_POLICY_RULE =
        "com.huawei.paas.cse.grayrelease.csefilter.GrayReleaseRulePolicyFilter";

    public static final String PROP_GRAYRELEASE_POLICY_RATE =
        "com.huawei.paas.cse.grayrelease.csefilter.GrayReleaseRatePolicyFilter";

    public String getGrayreleaseRulePolicy(String microservice, String microserviceQualifiedName) {
        return getProperty(null,
                PROP_GRAYRELEASE_ROOT + microserviceQualifiedName + "." + RULE_POLICY,
                PROP_GRAYRELEASE_ROOT + microservice + "." + RULE_POLICY);
    }

    public String getGrayreleaseRuleClassName(String microservice, String microserviceQualifiedName) {
        return getProperty(PROP_GRAYRELEASE_POLICY_RULE,
                PROP_GRAYRELEASE_ROOT + microserviceQualifiedName + "." + PROP_GRAYRELEASE_POLICYCLASS,
                PROP_GRAYRELEASE_ROOT + microservice + "." + PROP_GRAYRELEASE_POLICYCLASS);
    }

    public String getGrayreleaseInstanceGroupRule(String microservice) {
        return getProperty(null, PROP_GRAYRELEASE_ROOT + microservice + "." + PROP_GRAYRELEASE_GROUP_POLICY);
    }
}
